#!/bin/bash

# Dante Server 自动化安装脚本（强化依赖版）
# 适用于：CentOS 7/8、RHEL 7/8、Ubuntu 18.04/20.04/22.04、Debian 9/10/11

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # 无颜色

# 检查是否为root用户
if [ "$(id -u)" -ne 0 ]; then
   echo -e "${RED}错误：请使用root用户运行此脚本！${NC}"
   exit 1
fi

# 定义核心变量（优先使用官方源）
DANTE_VERSION="1.4.2"
DANTE_OFFICIAL_URL="https://www.inet.no/dante/files/dante-${DANTE_VERSION}.tar.gz"  # 官方源（优先）
DANTE_BACKUP_URL="https://gitee.com/tdcn/dante/raw/master/dante-${DANTE_VERSION}.tar.gz"  # 备用源
SOURCE_DIR="/usr/local/src"
CONFIG_FILE="/etc/danted.conf"
LOG_FILE="/var/log/dante_install.log"
SOCKS_PORT="23568"  # 自定义端口


# 日志函数（同时输出到控制台和日志）
log() {
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}


# 1. 安装依赖（强化版：明确列出所有必要依赖，取消静默输出以便排查）
install_dependencies() {
    log "${YELLOW}===== 开始安装编译依赖（关键步骤，请勿中断）=====${NC}"
    
    if [ -f /etc/redhat-release ]; then
        # CentOS/RHEL 系统依赖（包含开发工具链和核心库）
        log "${YELLOW}检测到 RHEL 系系统，安装依赖...${NC}"
        # 安装开发工具组（包含gcc、make等核心编译工具）
        yum groupinstall -y "Development Tools"
        # 安装具体依赖库（pam/openssl开发库、下载工具等）
        yum install -y pam-devel openssl-devel wget tar net-tools
    elif [ -f /etc/debian_version ]; then
        # Ubuntu/Debian 系统依赖
        log "${YELLOW}检测到 Debian 系系统，更新源并安装依赖...${NC}"
        # 更新源（避免依赖版本不匹配）
        apt update -y
        # 安装开发工具链（build-essential包含gcc、make等）
        apt install -y build-essential
        # 安装具体依赖库
        apt install -y libpam0g-dev libssl-dev wget tar net-tools
    else
        log "${RED}错误：不支持的操作系统！仅支持 CentOS/RHEL 7+/Ubuntu 18+/Debian 9+${NC}"
        exit 1
    fi
    
    # 检查依赖安装是否成功
    if [ $? -ne 0 ]; then
        log "${RED}依赖安装失败！可能原因：${NC}"
        log "${RED}1. 系统源配置错误（请检查/etc/yum.repos.d/或/etc/apt/sources.list）${NC}"
        log "${RED}2. 网络连接问题（请确保服务器能访问公网）${NC}"
        log "${RED}3. 权限不足（请确认以root用户运行）${NC}"
        exit 1
    fi
    
    log "${GREEN}===== 所有依赖安装完成 ====${NC}"
}


# 2. 下载并编译Dante（优先官方源，保留备用）
compile_dante() {
    log "${YELLOW}===== 开始下载并编译 Dante ${DANTE_VERSION} ====${NC}"
    
    # 确保源码目录存在
    mkdir -p "$SOURCE_DIR" && cd "$SOURCE_DIR"
    
    # 优先从官方源下载（更可靠）
    log "${YELLOW}从官方源下载源码包：${DANTE_OFFICIAL_URL}${NC}"
    wget -t 3 "$DANTE_OFFICIAL_URL" -O "dante-${DANTE_VERSION}.tar.gz"
    
    # 若官方源下载失败，自动切换到备用源
    if [ $? -ne 0 ]; then
        log "${YELLOW}官方源下载失败，尝试备用源：${DANTE_BACKUP_URL}${NC}"
        wget -t 3 "$DANTE_BACKUP_URL" -O "dante-${DANTE_VERSION}.tar.gz"
        if [ $? -ne 0 ]; then
            log "${RED}所有源下载失败！请检查网络或手动下载源码包到${SOURCE_DIR}${NC}"
            exit 1
        fi
    fi
    
    # 解压源码包（检查完整性）
    log "${YELLOW}解压源码包...${NC}"
    tar zxf "dante-${DANTE_VERSION}.tar.gz"
    if [ $? -ne 0 ]; then
        log "${RED}源码包解压失败！可能是包损坏，请重新下载${NC}"
        exit 1
    fi
    cd "dante-${DANTE_VERSION}"
    
    # 配置编译选项（保留详细日志，方便排查）
    log "${YELLOW}配置编译参数（这一步可能需要1-2分钟）...${NC}"
    ./configure --prefix=/usr/local/dante \
                --with-pam \
                --with-openssl \
                > "${LOG_FILE}.configure" 2>&1
    if [ $? -ne 0 ]; then
        log "${RED}配置失败！详细日志：${LOG_FILE}.configure${NC}"
        log "${RED}常见原因：依赖库缺失（请检查上面的依赖安装步骤）${NC}"
        exit 1
    fi
    
    # 编译（显示进度，避免用户误以为卡住）
    log "${YELLOW}开始编译（这一步可能需要3-5分钟，取决于服务器性能）...${NC}"
    make -j $(nproc) > "${LOG_FILE}.make" 2>&1  # 多线程编译加速
    if [ $? -ne 0 ]; then
        log "${RED}编译失败！详细日志：${LOG_FILE}.make${NC}"
        log "${RED}关键错误片段：$(grep -i 'error' ${LOG_FILE}.make | tail -n 10)${NC}"
        exit 1
    fi
    
    # 安装
    log "${YELLOW}安装到 /usr/local/dante...${NC}"
    make install > "${LOG_FILE}.install" 2>&1
    if [ $? -ne 0 ]; then
        log "${RED}安装失败！详细日志：${LOG_FILE}.install${NC}"
        exit 1
    fi
    
    # 强制验证可执行文件（核心检查）
    if [ ! -f "/usr/local/dante/sbin/danted" ]; then
        log "${RED}致命错误：未生成danted可执行文件！${NC}"
        log "${RED}可能原因：编译过程被中断/源码包损坏/系统环境不兼容${NC}"
        exit 1
    fi
    
    log "${GREEN}===== Dante 编译安装完成 ====${NC}"
}


# 3. 配置Dante（自动适配网卡）
configure_dante() {
    log "${YELLOW}===== 配置 Dante 服务 ====${NC}"
    
    # 自动检测默认网卡（优先取默认路由的网卡，更可靠）
    DEFAULT_IFACE=$(ip route show default | awk '/default/ {print $5}')
    if [ -z "$DEFAULT_IFACE" ]; then
        DEFAULT_IFACE="eth0"
        log "${YELLOW}未检测到默认网卡，使用 fallback 值：${DEFAULT_IFACE}${NC}"
    else
        log "${GREEN}检测到默认网卡：${DEFAULT_IFACE}${NC}"
    fi
    
    # 创建配置文件（使用23568端口，无认证）
    cat > "$CONFIG_FILE" << EOF
logoutput: /var/log/danted.log  # 独立日志文件，方便排查连接问题
internal: ${DEFAULT_IFACE} port = ${SOCKS_PORT}  # 监听端口
external: ${DEFAULT_IFACE}

method: none  # 无认证（如需密码认证，可改为 "username" 并配置PAM）

user.privileged: root
user.unprivileged: nobody

# 允许所有客户端连接
client pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    log: connect disconnect error
}

# 允许所有SOCKS命令（connect/bind/udpassociate）
socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    command: bind connect udpassociate
    log: connect disconnect error
}
EOF
    
    # 创建日志文件并授权
    touch /var/log/danted.log
    chmod 644 /var/log/danted.log  # 确保服务有权限写入日志
    
    log "${GREEN}===== Dante 配置完成 ====${NC}"
}


# 4. 创建系统服务（兼容systemd）
create_service() {
    log "${YELLOW}===== 创建系统服务 ====${NC}"
    
    if [ -f /etc/redhat-release ]; then
        # CentOS/RHEL 服务文件路径
        SERVICE_FILE="/usr/lib/systemd/system/danted.service"
    else
        # Ubuntu/Debian 服务文件路径
        SERVICE_FILE="/etc/systemd/system/danted.service"
    fi
    
    # 写入服务配置（增加自动重启机制）
    cat > "$SERVICE_FILE" << EOF
[Unit]
Description=Dante SOCKS5 Proxy Server
After=network.target

[Service]
Type=forking
PIDFile=/var/run/danted.pid
ExecStart=/usr/local/dante/sbin/danted -D -f ${CONFIG_FILE}  # 指定配置文件路径
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure  # 服务崩溃时自动重启
RestartSec=3  # 重启间隔3秒
User=root

[Install]
WantedBy=multi-user.target
EOF
    
    # 重载systemd配置
    systemctl daemon-reload
    
    log "${GREEN}===== 系统服务创建完成 ====${NC}"
}


# 5. 配置防火墙（开放端口）
configure_firewall() {
    log "${YELLOW}===== 配置防火墙（开放 ${SOCKS_PORT} 端口）=====${NC}"
    
    if [ -f /etc/redhat-release ]; then
        # CentOS/RHEL 防火墙配置
        if command -v firewalld > /dev/null 2>&1; then
            log "${YELLOW}使用 firewalld 开放端口...${NC}"
            firewall-cmd --add-port="${SOCKS_PORT}/tcp" --permanent
            firewall-cmd --reload
            # 验证
            if firewall-cmd --list-ports | grep -q "${SOCKS_PORT}/tcp"; then
                log "${GREEN}firewalld 已开放 ${SOCKS_PORT} 端口${NC}"
            else
                log "${YELLOW}警告：firewalld 端口开放可能未生效，请手动检查${NC}"
            fi
        elif command -v iptables > /dev/null 2>&1; then
            log "${YELLOW}使用 iptables 开放端口...${NC}"
            iptables -I INPUT -p tcp --dport "${SOCKS_PORT}" -j ACCEPT
            service iptables save
            # 验证
            if iptables -L INPUT | grep -q "${SOCKS_PORT}"; then
                log "${GREEN}iptables 已开放 ${SOCKS_PORT} 端口${NC}"
            else
                log "${YELLOW}警告：iptables 端口开放可能未生效，请手动检查${NC}"
            fi
        fi
    else
        # Ubuntu/Debian 防火墙配置
        if command -v ufw > /dev/null 2>&1; then
            log "${YELLOW}使用 ufw 开放端口...${NC}"
            ufw allow "${SOCKS_PORT}/tcp"
            ufw reload
            # 验证
            if ufw status | grep -q "${SOCKS_PORT}/tcp"; then
                log "${GREEN}ufw 已开放 ${SOCKS_PORT} 端口${NC}"
            else
                log "${YELLOW}警告：ufw 端口开放可能未生效，请手动检查${NC}"
            fi
        elif command -v iptables > /dev/null 2>&1; then
            log "${YELLOW}使用 iptables 开放端口...${NC}"
            iptables -I INPUT -p tcp --dport "${SOCKS_PORT}" -j ACCEPT
            iptables-save > /etc/iptables/rules.v4
            # 验证
            if iptables -L INPUT | grep -q "${SOCKS_PORT}"; then
                log "${GREEN}iptables 已开放 ${SOCKS_PORT} 端口${NC}"
            else
                log "${YELLOW}警告：iptables 端口开放可能未生效，请手动检查${NC}"
            fi
        fi
    fi
    
    log "${GREEN}===== 防火墙配置完成 ====${NC}"
}


# 6. 启动服务并验证
start_verify() {
    log "${YELLOW}===== 启动 Dante 服务并验证 ====${NC}"
    
    # 启动服务并设置开机自启
    systemctl start danted
    systemctl enable danted > /dev/null 2>&1
    
    # 等待服务启动（避免检测过早）
    sleep 3
    
    # 验证服务状态
    if systemctl is-active --quiet danted; then
        log "${GREEN}Dante 服务启动成功！${NC}"
        
        # 验证端口监听
        if netstat -tulpn | grep -q ":${SOCKS_PORT}"; then
            log "${GREEN}Dante 正在监听 ${SOCKS_PORT} 端口（正常）${NC}"
        else
            log "${YELLOW}警告：未检测到 ${SOCKS_PORT} 端口监听，但服务状态正常，可能是延迟${NC}"
        fi
        
        # 输出最终安装信息
        log "${GREEN}\n===== 安装成功！关键信息汇总 ====="
        log "服务器IP：$(hostname -I | awk '{print $1}')"
        log "SOCKS5端口：${SOCKS_PORT}"
        log "认证方式：无（如需密码认证，需修改 ${CONFIG_FILE}）"
        log "服务管理：systemctl [start|stop|restart|status] danted"
        log "连接日志：/var/log/danted.log"
        log "====================================${NC}"
    else
        log "${RED}Dante 服务启动失败！${NC}"
        log "${RED}服务状态详情：$(systemctl status danted --no-pager | grep -A 5 'Active:')${NC}"
        log "${RED}最近错误日志：$(journalctl -u danted -n 10 --no-pager)${NC}"
        log "${YELLOW}排查建议：${NC}"
        log "${YELLOW}1. 检查配置文件网卡是否正确：cat ${CONFIG_FILE} | grep 'internal:'${NC}"
        log "${YELLOW}2. 检查端口是否被占用：netstat -tulpn | grep ${SOCKS_PORT}${NC}"
        log "${YELLOW}3. 查看详细日志：cat /var/log/danted.log${NC}"
        exit 1
    fi
}


# 主函数：按顺序执行所有步骤
main() {
    # 清空旧日志（避免混淆）
    > "$LOG_FILE"
    log "${GREEN}===== 开始执行 Dante ${DANTE_VERSION} 自动化安装脚本 ====${NC}"
    
    install_dependencies   # 优先确保依赖完整
    compile_dante          # 下载编译（官方源优先）
    configure_dante        # 配置服务
    create_service         # 创建系统服务
    configure_firewall     # 开放端口
    start_verify           # 启动并验证
    
    log "${GREEN}===== 所有步骤执行完成，Dante 已成功安装 ====${NC}"
}

# 执行主函数
main